import {
  ROOM_STATUS,
  PLAYER_STATUS,
  roomStatusToString,
  playerStatusToString
} from "../../STATUS";
import render_player, {
  init_loader as render_player_init_loader
} from "./render_player";
import Vue from "vue";
import TWEEN, {
  L_ANI_TIME,
  B_ANI_TIME,
  M_ANI_TIME,
  S_ANI_TIME,
  Tween
} from "../../core/Tween";
import { SCORE_TYPE } from "../../STATUS";
import Card, { CardList, CARD_LIST } from "../../core/Card";
import { vueStageComponentWrapper } from "../../core/componentGenerator";
export default vueStageComponentWrapper("end-game", {
  data() {
    return {
      ROOM_STATUS,
      PLAYER_STATUS,
      msg: "Welcome to Your Vue.js App"
    };
  },
  resources: {
    RPIL: render_player_init_loader,
    CSIL: PIXI.CardSpirte.init_loader,

    straight_flush_score: "game/paixing09.png",
    four_score: "game/paixing08.png",
    full_house_score: "game/paixing07.png",
    flush_score: "game/paixing06.png",
    straight_score: "game/paixing05.png",
    three_score: "game/paixing04.png",
    two_pair_score: "game/paixing03.png",
    two_score: "game/paixing02.png",
    any_score: "game/paixing01.png",

    three_straight_score: "game/paixing11.png",
    three_flush_score: "game/paixing12.png",
    six_pair_score: "game/paixing10.png",
    one_long_score: "game/paixing13.png",
    king_long_score: "game/paixing14.png",
    all_small_score: "game/paixing16.png",
    all_big_score: "game/paixing15.png",

    score_bg: "game/Game_UI_03.png",
    score_bg_special: "game/Game_UI_06.png",
    score_bg_head_win: "game/Victory.png",
    score_bg_head_fail: "game/Failure.png",
    confirm: "home/choujiang_confirm.png",

    show_score_dialog: "game/xs.png",
    hide_score_dialog: "game/yc.png",

    gun: "game/gun.png",
    boom1: "game/boom1.png",
    boom2: "game/boom2.png",
    boom3: "game/boom3.png",
    boom4: "game/boom4.png",
    hole1: "game/hole_file.png",
    hole2: "game/hole.png"
  },
  next_stages: ["home"],
  created() {
    const { unwatchers, app, loader } = this;
    loader.onError.add(err => console.error(err));
    const ani_tween = new TWEEN();
    app._ticker.add(() => {
      // 动画控制器
      ani_tween.update();
    });
    this.draw_app = () => {
      console.log("DRAW WAITGAMER");
      const loader = this.loader;
      if (!loader) {
        // maybe run on after destroyed
        return;
      }
      this.clearWatch();
      const resources = loader.resources;
      app.stage.destroy();
      const stage = (app.stage = new PIXI.Container());
      const { width, height } = app.renderer;
      const bg = new PIXI.Sprite(resources.bg.texture);
      bg.width = width;
      bg.height = height;
      stage.addChild(bg);

      let is_inited = false;
      unwatchers[unwatchers.length] = this.$watch(
        "room.data",
        async data => {
          if (!data) {
            return;
          }
          if (is_inited) {
            return;
          }
          is_inited = true;
          const { results_list, players } = this.room.data;

          const {
            avatar_box_bounds,
            $cur_player,
            $other_players
          } = await render_player.call(this, {
            app,
            stage,
            resources,
            width,
            height,
            un_watch: true,
            players: players,
            unwatchers
          });

          const results = results_list.find(
            results => results.player_id === this.player.id
          );
          if (!results) {
            return;
          }
          // console.log(JSON.stringify(results, null, 2));

          function render_res_cards(
            submit_res_cards,
            submit_res_scores,
            $parent,
            pos_index = 0,
            gun = 1 /*打枪信息*/
          ) {
            // 显示卡牌
            const $res_container = new PIXI.Container();
            $parent.addChild($res_container);
            const cur_player_bounds = $cur_player.getBounds();
            // 牌型名字
            const $score_container = new PIXI.Container();
            $parent.addChild($score_container);

            if (width > height) {
              var res_width = width / 3;
              var res_height = height / 2;
              if (pos_index === 0) {
                $res_container.x = res_width;
                $res_container.y = res_height;
              } else if (pos_index === 1) {
                $res_container.x = res_width;
                $res_container.y = 0;
              } else if (pos_index === 2) {
                $res_container.x = 0;
                $res_container.y = res_height / 2;
              } else if (pos_index === 3) {
                $res_container.x = res_width * 2;
                $res_container.y = res_height / 2;
              }
            } else {
              var res_width = width / 2;
              var res_height = height / 3;
              if (pos_index === 0) {
                $res_container.x = res_width / 2;
                $res_container.y = res_height * 2;
              } else if (pos_index === 1) {
                $res_container.x = res_width / 2;
                $res_container.y = 0;
              } else if (pos_index === 2) {
                $res_container.x = 0;
                $res_container.y = res_height;
              } else if (pos_index === 3) {
                $res_container.x = res_width;
                $res_container.y = res_height;
              }
            }

            let ani_cards = ani_tween.Tween({}).to({}, 0).start();
            ["top", "mid", "btm"].forEach((type, j) => {
              if (!submit_res_cards[type]) {
                return;
              }
              const $cards_container = new PIXI.Container();
              const card_list = submit_res_cards[type].map(Card.getIns);
              card_list.forEach((card, i) => {
                const $card = new PIXI.CardSpirte(card, resources);
                $card.x = $card.width * (i * 0.58 - 0.02);
                $cards_container.addChild($card);
              });
              if (j == 2) {
                $cards_container.maxWidthHeight(
                  res_width / 5 * 4,
                  res_height / 8 * 4
                );
              } else {
                $cards_container.maxWidthHeight(
                  res_width / 5 * (j + 3),
                  res_height / 8 * (j + 3)
                );
              }
              $cards_container.x = res_width / 2 - $cards_container.width / 2;
              $cards_container.y = res_height / 4 * j;
              $res_container.addChild($cards_container);

              // 显示牌型名字
              const score_type = SCORE_TYPE.get(
                submit_res_scores[type].handle_weight
              );
              let $score_type;
              let score_type_ani;
              if (score_type) {
                $score_type = new PIXI.Sprite(
                  resources[score_type + "_score"].texture
                );
                $score_type.maxWidth(res_width / 4);
                $score_type.x = $res_container.x; //- $score_type.width * 1.2
                $score_type.y =
                  $res_container.y +
                  $cards_container.y +
                  $cards_container.height / 2 -
                  $score_type.height / 2;
                $score_container.addChild($score_type);
                // 动画
                score_type_ani = ani_tween
                  .Tween($score_type)
                  .fadeIn(B_ANI_TIME);
              }
              // 动画
              const new_ani_cards = ani_tween
                .Tween($cards_container)
                .zoomIn(B_ANI_TIME)
                .delay(B_ANI_TIME);
              if ($score_type) {
                new_ani_cards.chain(score_type_ani);
              }

              ani_cards.chain(new_ani_cards);
              ani_cards = new_ani_cards;
            });

            // 特殊牌的直接显示：一排直接显示
            if (submit_res_cards.all) {
              const $cards_container = new PIXI.Container();
              const card_list = submit_res_cards.all
                .map(Card.getIns)
                .sort((card_a, card_b) => card_a - card_b);
              const $card_list = card_list.map((card, i) => {
                const $card = new PIXI.CardSpirte(card, resources);
                // $card.x = $card.width * (i * .35 - 0.02);
                $cards_container.addChild($card);
                ani_tween
                  .Tween($card)
                  .to(
                    {
                      rotation: Math.PI / 11 * -(card_list.length / 2 - i - 0.5)
                    },
                    1000
                  )
                  .onStart(() => {
                    $card.pivot.set($card.width / 2, $card.height * 1.5);
                    $card.x += $card.width / 2;
                    $card.y += $card.height * 1.5;
                  })
                  .delay(1000)
                  .start();
                // $card.rotation = ;
                return $card;
              });
              const unit_card_width = res_width * 1.4 / 5.53;
              $cards_container.maxWidth(unit_card_width);
              // $card_list.forEach($card=>{
              //   $card.x = 0;
              // });
              $cards_container.x = res_width / 2 - unit_card_width / 2;
              $cards_container.y = res_height / 4;
              $res_container.addChild($cards_container);

              // 显示牌型名字
              const score_type = SCORE_TYPE.get(
                submit_res_scores.top.handle_weight
              );
              let $score_type;
              let score_type_ani;
              if (score_type) {
                $score_type = new PIXI.Sprite(
                  resources[score_type + "_score"].texture
                );
                $score_type.maxHeight(res_height / 4);
                $score_type.x = res_width / 2 - $score_type.width / 2;
                $score_type.y = res_height * 3 / 4 - $score_type.height / 2;
                $res_container.addChild($score_type);
                // 动画
                score_type_ani = ani_tween
                  .Tween($score_type)
                  .fadeIn(B_ANI_TIME);
              }

              // 动画
              const new_ani_cards = ani_tween
                .Tween($cards_container)
                .zoomIn(B_ANI_TIME)
                .delay(B_ANI_TIME);
              if ($score_type) {
                new_ani_cards.chain(score_type_ani);
              }

              ani_cards.chain(new_ani_cards);
              ani_cards = new_ani_cards;
            }
            $res_container.x += res_width * 0.1;
            $res_container.y += res_height * 0.1;
            $res_container.scale.set(0.8);

            // 显示打枪
            $parent.getResContainer = () => {
              return $res_container;
            };
            ani_cards.onComplete(() => {
              setTimeout(function() {
                $parent.emit("animation-complete", $res_container);
              }, B_ANI_TIME / 20);
            });
            // if(gun >= 2){
            // }else if(gun <= -2){

            // }
          }

          const PLAYER_RES_PLANEL_MAP = new Map();

          // 显示用户的牌组面板
          const $res_cards_parent_cur = new PIXI.Container();
          stage.addChild($res_cards_parent_cur);
          PLAYER_RES_PLANEL_MAP.set(this.player.id, $res_cards_parent_cur);
          ani_tween
            .Tween($cur_player)
            .to(
              {
                x: $cur_player.x +
                  (-width / (width > height ? 6 : 4) -
                    avatar_box_bounds.width / 2)
              },
              B_ANI_TIME
            )
            .start()
            // .onComplete(()=>{
            .onComplete(() => {
              render_res_cards(
                results.submit_res_cards,
                results.submit_res_scores,
                $res_cards_parent_cur,
                0
              );
            });
          const [
            $other_player_1,
            $other_player_2,
            $other_player_3
          ] = $other_players.children;
          [
            $other_player_1,
            $other_player_2,
            $other_player_3
          ].forEach(($other_player, i) => {
            if ($other_player) {
              $other_player.setStatusHandler($status => {
                const player = this.room.players.find(
                  player => player.id === $other_player.player_id
                );
                // console.log("recheck status",player)
                if (player) {
                  if (player.status === PLAYER_STATUS.READY) {
                    $status.visible = true;
                  } else {
                    $status.visible = false;
                  }
                } else {
                  // 离开房间，考虑到可能还会重新进入房间，$status对象必须改为单一对象才能使用$watch
                }
              });
              const $res_cards_parent = new PIXI.Container();
              stage.addChild($res_cards_parent);
              const one_vs_one = results.one_vs_one_list.find(
                one_vs_one => one_vs_one.player_id === $other_player.player_id
              );
              PLAYER_RES_PLANEL_MAP.set(
                one_vs_one.player_id,
                $res_cards_parent
              );

              const ani_to = {};
              if (i === 0) {
                ani_to.x = $other_player.x + width / (width > height ? 6 : 4); //+ avatar_box_bounds.width / 2;
              }
              ani_tween
                .Tween($other_player)
                .to(ani_to, B_ANI_TIME)
                .start()
                .onComplete(() => {
                  // 显示卡牌
                  render_res_cards(
                    one_vs_one.submit_res_cards,
                    one_vs_one.submit_res_scores,
                    $res_cards_parent,
                    i + 1,
                    one_vs_one.multiple
                  );
                });
            }
          });

          // 枪与子弹的容器
          const $gun_bullet_container = new PIXI.Container();
          stage.addChild($gun_bullet_container);

          // 显示隐藏分数面板按钮
          const $toggle_btm = new PIXI.Sprite(
            resources.show_score_dialog.texture
          );
          let $score_dialog;
          // 分数面板
          let _inited_show_score_dialog = false;
          // 用户头像组
          const player_ins = [];
          const show_score_dialog = () => {
            if (_inited_show_score_dialog) {
              return false;
            }
            _inited_show_score_dialog = true;
            $score_dialog = (() => {
              const $dialog = new PIXI.Container();
              const $bg_mask = new PIXI.Graphics();
              $bg_mask.beginFill(0x0, 0.8);
              $bg_mask.drawRect(0, 0, width, height);
              $bg_mask.endFill();
              $dialog.addChild($bg_mask);

              // 计分面板
              const $bg = new PIXI.Sprite(resources.score_bg_special.texture);
              $bg.maxWidthHeight(width * 0.8, height * 0.8);
              $bg.x = width / 2 - $bg.width / 2;
              $bg.y = height / 2 - $bg.height / 2;
              $bg.tint = results.total >= 0 ? 0xffff22 : 0xffffff;
              $dialog.addChild($bg);

              // 头部
              const $bg_title = new PIXI.Sprite(
                resources[
                  results.total >= 0
                    ? "score_bg_head_win"
                    : "score_bg_head_fail"
                ].texture
              );
              $bg_title.maxWidth($bg.width * 0.8);
              $bg_title.x = $bg.x + $bg.width / 2 - $bg_title.width / 2;
              $bg_title.y = $bg.y - $bg_title.height * 0.35;
              $dialog.addChild($bg_title);

              // 分数
              const fontSize = $bg.width / 30;
              const minFontSize = fontSize / 2;

              // $dialog.addChild($cur_player);
              // $dialog.addChild($other_players);
              // 用户组
              const $players = new PIXI.Container();
              $players.addChild($cur_player);
              $players.addChild(...$other_players.children);
              $dialog.addChild($players);
              const unit_width = $bg.width / ($players.children.length + 1);
              $players.children.forEach(($player, i) => {
                player_ins.push($player);
                $player._backup_1 = {
                  width: $player.width,
                  height: $player.height,
                  x: $player.x,
                  y: $player.y,
                  parent: $other_players
                };
                const _backup_2 = ($player._backup_2 = {
                  parent: $players
                });

                const res_height = Math.min($bg.height * 0.4, $player.height);
                const { height: old_height } = $player;
                $player.maxHeight(res_height);
                _backup_2.width = $player.width;
                _backup_2.height = $player.height;
                const { width: new_width, height: new_height } = $player;
                $player.maxHeight(old_height);
                const new_avatar_box_width =
                  new_height / old_height * avatar_box_bounds.width;

                ani_tween
                  .Tween(
                    Object.assign(
                      {
                        height: $player.width
                      },
                      $player.getPos()
                    )
                  )
                  .to(
                    {
                      x: (_backup_2.x =
                        (i + 1) * unit_width - new_avatar_box_width / 2),
                      y: (_backup_2.y = 0),
                      height: new_height
                    },
                    B_ANI_TIME
                  )
                  .onUpdate(function() {
                    $player.moveTo(this.x, this.y);
                    $player.maxHeight(this.height);
                  })
                  .onComplete(() => {
                    const player_results = results_list.find(
                      player_results =>
                        player_results.player_id === $player.player_id
                    );
                    if (player_results) {
                      const info = player_results.total;
                      let color = 0xffffff;
                      if (typeof info === "number") {
                        if (info > 0) {
                          info = "+" + info;
                          color = 0x00ff33;
                        } else {
                          info = " " + info;
                          color = 0xff0033;
                        }
                      }
                      $player.showText(
                        new PIXI.Text(info, {
                          fill: color,
                          fontSize: fontSize
                        })
                      );
                    }
                  })
                  .start();
              });
              ani_tween
                .Tween($players)
                .to(
                  {
                    x: $bg.x,
                    y: $bg.y + $bg.height * 0.2
                  },
                  B_ANI_TIME
                )
                .start();

              // 描述与按钮
              const $info = new PIXI.Text("点击确定，即可开始下一局游戏", {
                fill: 0xffffff,
                fontSize
              });
              $info.x = $bg.x + $bg.width / 2 - $info.width / 2;
              $info.y = $bg.y + $bg.height * 0.7 - $info.height / 2;
              $dialog.addChild($info);
              const $btm = new PIXI.Sprite(resources.confirm.texture);

              $btm.maxWidth(fontSize * 7);
              $btm.x = $bg.x + $bg.width / 2 - $btm.width / 2;
              $btm.y = $bg.y + $bg.height * 0.85 - $btm.height / 2;
              $dialog.addChild($btm);
              $btm.hover(
                () => $btm.tint = 0x999999,
                () => $btm.tint = 0xffffff
              );
              $btm.bindTap(() => {
                this.restartGame();
              });

              return $dialog;
            })();
            stage.addChildBefore($score_dialog, $toggle_btm);
            // ani_tween.Tween($score_dialog)
            //   .fadeIn(B_ANI_TIME)
            //   .start()
            //   .onComplete(()=>{
            //   });
            // $score_dialog.visible = false;
            return $score_dialog;
          };

          // 按钮的操作
          let show = false;
          let cur_ani;
          const click_show_score_dialog = () => {
            show_score_dialog();
            if (cur_ani) {
              ani_tween.remove(cur_ani);
            }
            const { width, height } = $toggle_btm;
            if (show) {
              $toggle_btm.texture = resources.show_score_dialog.texture;
              cur_ani = ani_tween
                .Tween($score_dialog)
                .fadeOut(B_ANI_TIME, $score_dialog.alpha)
                .start()
                .onComplete(() => {
                  player_ins.forEach($player => {
                    const _backup_1 = $player._backup_1;
                    for (let k in _backup_1) {
                      if (k === "parent") {
                        _backup_1[k].addChild($player);
                      } else {
                        $player[k] = _backup_1[k];
                      }
                    }
                  });
                  $score_dialog.visible = false;
                });
            } else {
              $toggle_btm.texture = resources.hide_score_dialog.texture;
              cur_ani = ani_tween
                .Tween($score_dialog)
                .fadeIn(B_ANI_TIME, $score_dialog.alpha)
                .start()
                .onStart(() => {
                  player_ins.forEach($player => {
                    const _backup_2 = $player._backup_2;
                    for (let k in _backup_2) {
                      if (k === "parent") {
                        _backup_2[k].addChild($player);
                      } else {
                        $player[k] = _backup_2[k];
                      }
                    }
                  });
                  $score_dialog.visible = true;
                });
            }
            $toggle_btm.width = width;
            $toggle_btm.height = height;
            show = !show;
          };
          $toggle_btm.bindTap(click_show_score_dialog);
          $toggle_btm.maxWidthHeight(width * 0.1, height * 0.3);
          $toggle_btm.x = width * 0.9 - $toggle_btm.width / 2;
          $toggle_btm.y = height - $toggle_btm.height;
          stage.addChild($toggle_btm);
          // setTimeout(()=>{

          // }, 3000);

          /* 打枪动画*/
          const boom_frames = [];
          const hole_frames = [];

          const fly_bullet = (from_x, from_y, to_x, to_y, cb) => {
            if (!boom_frames.length) {
              for (let i = 1; i <= 4; i++) {
                // magically works since the spritesheet was loaded with the pixi loader
                boom_frames.push(resources["boom" + i].texture);
              }
              for (let i = 1; i <= 2; i++) {
                // magically works since the spritesheet was loaded with the pixi loader
                hole_frames.push(resources["hole" + i].texture);
              }
            }
            const boom_ani = new PIXI.extras.AnimatedSprite(boom_frames);
            boom_ani.maxWidthHeight(width / 8, height / 8);
            boom_ani.anchor.set(0.5);
            boom_ani.animationSpeed = 0.1;
            boom_ani.loop = false;
            $gun_bullet_container.addChild(boom_ani);
            boom_ani.play();
            // 子弹移动的轨道
            ani_tween
              .Tween(boom_ani)
              .set({
                x: from_x,
                y: from_y,
                alpha: 0
              })
              .to(
                {
                  x: to_x,
                  y: to_y,
                  alpha: 1
                },
                B_ANI_TIME
              )
              .easing(TWEEN.Easing.Cubic.Out)
              .start();
            boom_ani.onComplete = function() {
              boom_ani.destroy();
              // 留下弹孔
              const hole_ani = new PIXI.extras.AnimatedSprite(hole_frames);
              hole_ani.maxWidthHeight(width / 8, height / 8);
              hole_ani.maxWidth(
                hole_ani.width * (1 + (Math.random() - 0.5) / 2)
              );
              // hole_ani.rotation = Math.random()*Math.PI; // 旋转会使贴图的光影效果不对
              hole_ani.x = to_x;
              hole_ani.y = to_y;
              hole_ani.alpha = 0.9;
              hole_ani.anchor.set(0.5);
              hole_ani.animationSpeed = 0.1;
              hole_ani.loop = false;
              $gun_bullet_container.addChild(hole_ani);
              hole_ani.play();
              hole_ani.onComplete = cb;
            };
          };
          function get_two_point_deg(center_x, center_y, x, y) {
            let turn_deg =
              Math.atan((center_x - x) / (center_y - y)) * 180 / Math.PI;
            // turn_deg = -turn_deg;
            // turn_deg -= 90;
            if (y > center_y) {
              if (x < center_x) {
                turn_deg -= 180;
              } else {
                turn_deg += 180;
              }
            }
            return turn_deg;
          }
          function boom_from_gun(gun_x, gun_y, boom_x, boom_y, ani) {
            const $gun = new PIXI.Sprite(resources.gun.texture);
            $gun.maxWidthHeight(width / 4, height / 4);
            $gun.anchor.set(0.4, 0.2);
            $gun.x = gun_x;
            $gun.y = gun_y;
            $gun.rotation = Math.PI / 180 * -90;
            // let turn_deg = Math.atan((gun_y - boom_y) / (gun_x - boom_x)) * 180 / Math.PI;
            // if(turn_deg<0){
            //   turn_deg+=180;
            // }
            // turn_deg -= 90;
            // turn_deg = -turn_deg;
            // if(boom_y > gun_y){
            //   turn_deg+=180
            // }
            let turn_deg = get_two_point_deg(gun_x, gun_y, boom_x, boom_y);
            console.log("turn_deg", turn_deg);
            $gun.rotation += Math.PI / 180 * -turn_deg;
            $gun.fireBullet = function(to_x, to_y) {
              const res_rotation = this.rotation;
              const { x: from_x, y: from_y } = this;

              let _call_end_times = 0;
              this.on("fire-end", () => {
                _call_end_times += 1;
                if (_call_end_times === 2) {
                  ani_tween
                    .Tween(this)
                    .fadeOut()
                    .start()
                    .onComplete(() => this.destroy());
                }
              });
              const gun_end_ani = ani_tween
                .Tween(this)
                .to(
                  {
                    rotation: res_rotation
                  },
                  600
                )
                .onComplete(() => this.emit("fire-end"));
              const gun_start_ani = ani_tween
                .Tween(this)
                .to(
                  {
                    rotation: res_rotation - Math.PI / 180 * 20
                  },
                  120
                )
                .chain(gun_end_ani)
                .onStart(() => {
                  $gun_bullet_container.addChild(this);
                  fly_bullet(from_x, from_y, to_x, to_y, () =>
                    this.emit("fire-end")
                  );
                });
              ani.chain(gun_start_ani);
              return gun_end_ani;
            };
            return $gun.fireBullet(boom_x, boom_y);
          }
          let gun_fire_ani = ani_tween.Tween({ a: 0 }).to({ a: 1 }, B_ANI_TIME);

          const first_gun_fire_ani = gun_fire_ani;
          results_list.forEach(results => {
            // console.log(JSON.stringify(results,null,2))
            const $res_cards_parent_1 = PLAYER_RES_PLANEL_MAP.get(
              results.player_id
            );
            $res_cards_parent_1.once("animation-complete", () => {
              const $res_container_1 = $res_cards_parent_1.getResContainer();
              const self_x = $res_container_1.x + $res_container_1.width / 2;
              const self_y = $res_container_1.y + $res_container_1.height / 2;
              const gun_fire_infos = results.one_vs_one_list
                .map(one_vs_one => {
                  if (Math.abs(one_vs_one.multiple) >= 2) {
                    const $res_cards_parent_2 = PLAYER_RES_PLANEL_MAP.get(
                      one_vs_one.player_id
                    );
                    const $res_container_2 = $res_cards_parent_2.getResContainer();
                    const res_width = $res_container_2.width;
                    const res_height = $res_container_2.height;
                    const target_x = $res_container_2.x + res_width / 2;
                    const target_y = $res_container_2.y + res_height / 2;
                    if (one_vs_one.top > 0) {
                      // 目标中弹
                      gun_fire_ani = boom_from_gun(
                        self_x,
                        self_y,
                        target_x + (Math.random() - 0.5) * res_width / 2,
                        target_y + (Math.random() - 0.5) * res_height / 2,
                        gun_fire_ani
                      );
                      return {
                        self_x,
                        self_y,
                        target_x,
                        target_y,
                        res_width,
                        res_height
                      };
                    }
                  }
                })
                .filter(info => info);
              if (gun_fire_infos.length === 3) {
                // 通杀额外的动画
                const new_gun_fire_ani = ani_tween.Tween({}).to({}, 1);
                let ani_times = 0;
                const complete_cb = () => {
                  ani_times += 1;
                  if (ani_times === 6) {
                    new_gun_fire_ani.start();
                  }
                };
                gun_fire_ani.onComplete(() => {
                  for (let {
                    target_x,
                    target_y,
                    res_width,
                    res_height
                  } of gun_fire_infos) {
                    setTimeout(() => {
                      fly_bullet(
                        target_x,
                        target_y,
                        target_x + (Math.random() - 0.5) * res_width / 2,
                        target_y + (Math.random() - 0.5) * res_height / 2,
                        complete_cb
                      );
                    }, 500 * Math.random());
                    setTimeout(() => {
                      fly_bullet(
                        target_x,
                        target_y,
                        target_x + (Math.random() - 0.5) * res_width / 2,
                        target_y + (Math.random() - 0.5) * res_height / 2,
                        complete_cb
                      );
                    }, 1000 * Math.random());
                  }
                });
                gun_fire_ani = new_gun_fire_ani;
              }
              if (!first_gun_fire_ani.is____started) {
                first_gun_fire_ani.is____started = true;
                first_gun_fire_ani.start();
              }
            });
          });

          gun_fire_ani.onComplete(() => {
            setTimeout(() => {
              if (!_inited_show_score_dialog) {
                click_show_score_dialog();
              }
            }, 3000);
          });
        },
        { immediate: true }
      );
    };
  },
  methods: {
    // cartNameToHtml(card) {
    //   const card_info = card.split("_");
    //   const [type, num] = card_info;
    //   const symbol_map = {
    //     "黑桃": "♠",
    //     "方块": "♦",
    //     "红心": "♥",
    //     "梅花": "♣",
    //   };
    //   const color_map = {
    //     "黑桃": "#000",
    //     "方块": "#e30",
    //     "红心": "#F00",
    //     "梅花": "#333",
    //   };
    //   return `<div class='img' style="color:${color_map[type]};">
    //     <div class='symbol'>${symbol_map[type]}</div>
    //     <div class='number'>${num}</div>
    //   </div>`
    // },
    roomStatusToString,
    playerStatusToString,
    restartGame() {
      socket.emit("restart");
    },
    getTotalByPlayerId(player_id) {
      for (var results of this.room.data) {
        if (results.player_id === player_id) {
          return results.total;
        }
      }
    }
  }
});
